import { HttpException, Injectable } from '@nestjs/common';
import { CreateRoleDto } from './dto/create-role.dto';
import { UpdateRoleDto } from './dto/update-role.dto';
import { Repository } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';
import { SysRole } from 'src/entities/sys-role.entity';
import { SysMenu } from 'src/entities/sys-menu.entity';
import { RoleQueryDto } from './dto/query-role.dto';
import { AssignMenuDto } from '../menu/dto/assign-menu.dto';

@Injectable()
export class RolesService {
  constructor(
    @InjectRepository(SysRole)
    private roleRepository: Repository<SysRole>,
    @InjectRepository(SysMenu)
    private menuRepository: Repository<SysMenu>,
  ) {}

  async create(createRoleDto: CreateRoleDto): Promise<SysRole> {
    const role = new SysRole();
    Object.assign(role, createRoleDto);

    if (createRoleDto.menuIds) {
      role.menus = await this.menuRepository.findByIds(createRoleDto.menuIds);
    }

    return this.roleRepository.save(role);
  }

  async update(id: number, updateRoleDto: UpdateRoleDto): Promise<SysRole> {
    const role = await this.roleRepository.findOne({ where: { id } });
    if (!role) {
      throw new Error('Role not found');
    }

    Object.assign(role, updateRoleDto);

    if (updateRoleDto.menuIds) {
      role.menus = await this.menuRepository.findByIds(updateRoleDto.menuIds);
    }

    return this.roleRepository.save(role);
  }

  async findAll(query: RoleQueryDto) {
    const qb = this.roleRepository
      .createQueryBuilder('role')
      // .leftJoinAndSelect('role.menus', 'menu')
      .where('role.is_deleted = :isDeleted', { isDeleted: false });

    if (query.name) {
      qb.andWhere('role.name LIKE :name', { name: `%${query.name}%` });
    }

    if (query.status !== undefined) {
      qb.andWhere('role.status = :status', { status: query.status });
    }

    const total = await qb.getCount();
    let roles = await qb
      .skip((query.pageNum - 1) * query.pageSize)
      .take(query.pageSize)
      .getMany();

    // 创建新对象，避免修改实体
    const rolesList = roles.map((role) => {
      return {
        ...role,
        status: role.status ? 1 : 0, // 布尔值转为数字
      };
    });

    return { total, list: rolesList };
  }

  async remove(id: number): Promise<void> {
    await this.roleRepository.update(id, { is_deleted: true });
  }

  async assignMenus(
    id: number,
    assignMenuDto: AssignMenuDto,
  ) {
    const role_id = Number(id);
    const role = await this.roleRepository.findOne({
      where: { id: role_id, is_deleted: false },
      relations: ['menus'],
    });
    if (!role) {
      throw new HttpException('该用户不存在', 400);
    }

    role.menus = await this.menuRepository.findByIds(assignMenuDto.menuIds);
    await this.roleRepository.save(role);
    return {
      message: '分配菜单成功',
    }
  }

  async getRoleMenus(id: number) {
    const role = await this.roleRepository.findOne({
      where: { id, is_deleted: false },
      relations: ['menus'],
    });

    if (!role) {
      throw new HttpException('该角色不存在', 400);
    }

    return role.menus.map((menu) => menu.id);
  }

  async getRoleOptions() {
    const roles = await this.roleRepository.find({
      where: { is_deleted: false },
      select: ['id', 'name'],
      order: { sort: 'ASC' },
    });

    return roles.map((role) => ({
      value: role.id.toString(),
      label: role.name,
    }));
  }

  async findOne(id: number) {
    const role = await this.roleRepository.findOne({
      where: { id, is_deleted: false },
      relations: ['menus'],
    });

    if (!role) {
      throw new HttpException('该角色不存在', 400);
    }

    return {
      id: role.id,
      name: role.name,
      code: role.code,
      sort: role.sort,
      status: role.status ? 1 : 0,
      createTime: role.create_time,
      updateTime: role.update_time,
      menuIds: role.menus.map((menu) => menu.id),
    };
  }
}
